package ma.jeetconsulting.pocs.service;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Stack;

import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ModuleAnalyzer {
	private static final String POM_XML = "pom.xml";
	private static final String PROPERTY_END_PATTERN = "}";
	private static final String PROPERTY_START_PATTERN = "${";
	private Stack<Properties> moduleProperties;
	
	private Logger logger = LoggerFactory.getLogger(getClass());

	public List<Dependency> getDependencies(String modulePath) {
		try {
			return tryToGetDependencies(modulePath);
		} catch (FileNotFoundException e) {
			logger.error("Module is path : +" + modulePath + " doesn't exist ", e);
		} catch (IOException e) {
			logger.error("Error : Problem incountred when reading  +" + modulePath , e);
		} catch (XmlPullParserException e) {
			logger.error("Error : Problem accur when parsing " + modulePath, e);
		}

		return new ArrayList<>();
	}

	private List<Dependency> tryToGetDependencies(String modulePath)
			throws FileNotFoundException, IOException, XmlPullParserException {
		List<Dependency> allDependencies = new ArrayList<>();

		Model model = Utils.getPomObjectModel(modulePath);
		if(model != null) {
			if (model.getParent() != null) {
				allDependencies.addAll(getParentsDependency(modulePath, model));
			}
	
			allDependencies.addAll(model.getDependencies());
			updateDependenciesVersion(allDependencies, modulePath);
		}
		return allDependencies;
	}

	private void updateDependenciesVersion(List<Dependency> dependencies, String modulePath) throws IOException, XmlPullParserException {
		for (Dependency dependency : dependencies)
			if (versionIsIndicatedByAProperty(dependency))
				setReelProperty(dependency, getProperties(modulePath));
	}

	private void setReelProperty(Dependency dependency, Map<String, String> properties) {
		String currentProperty = properties.get(getPropertyName(dependency.getVersion()));
		dependency.setVersion(currentProperty);
	}

	private String getPropertyName(String version) {
		return version.substring(2, version.lastIndexOf(PROPERTY_END_PATTERN));
	}

	private boolean versionIsIndicatedByAProperty(Dependency dependency) {
		return dependency.getVersion().startsWith(PROPERTY_START_PATTERN);
	}

	private List<Dependency> getParentsDependency(String modulePath, Model model)
			throws FileNotFoundException, IOException, XmlPullParserException {
		List<Dependency> dependencies = new ArrayList<>();

		String parentPath = getParentPath(modulePath, model);
		Model parentModel = Utils.getPomObjectModel(parentPath);

		if (parentModel.getParent() != null)
			dependencies.addAll(getParentsDependency(parentPath, parentModel));

		dependencies.addAll(parentModel.getDependencies());
		return dependencies;
	}


	private String getParentPath(String modulePath, Model model) {
		return Paths.get(modulePath, model.getParent().getRelativePath())
				.normalize().toString().replace(File.separatorChar + POM_XML, "");
	}


	private Map<String, String> getProperties(String modulePath)
			throws IOException, XmlPullParserException {
		moduleProperties = new Stack<>();
		Map<String, String> allModuleProperties = new HashMap<>();

		Model moduleModel = Utils.getPomObjectModel(modulePath);
		moduleProperties.push(moduleModel.getProperties());

		if (moduleModel.getParent() != null) {
			getParentProperties(moduleModel.getParent(), modulePath);
		}

		while (!moduleProperties.empty()) {
			Properties properties = moduleProperties.pop();
			for (Entry<Object, Object> property : properties.entrySet()) {
				allModuleProperties.put(property.getKey().toString(), property
						.getValue().toString());
			}

		}
		return allModuleProperties;
	}

	private void getParentProperties(Parent parent, String modulePath)
			throws IOException, XmlPullParserException {
		String parentPath = Paths.get(modulePath, parent.getRelativePath())
				.normalize().toString().replace(File.separatorChar + POM_XML, "");
		Model parentModel = Utils.getPomObjectModel(parentPath);
		moduleProperties.push(parentModel.getProperties());
		if (parentModel.getParent() == null) {
			return;
		} else {
			getParentProperties(parentModel.getParent(), parentPath);
		}

	}

}
